home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / QuickTime VR / MacOS / QuickDraw™ 3D 1.0.6F4 SDK / Development / 3DMF parser / 1.0 version / MF3DPC / MFTEXTRD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-07  |  32.4 KB  |  1,172 lines  |  [TEXT/dosa]

  1. /*==============================================================================
  2.  *
  3.  *    File:        MFTEXTRD.C
  4.  *
  5.  *    Function:    Internal Read routines
  6.  *
  7.  *    Version:    Metafile:    Version 1.0 3DMF files
  8.  *                Package:    Release #2 of this code
  9.  *
  10.  *    Author(s):    Rick Wong (RWW), Duet Development Corp.
  11.  *                John Kelly (JRK), Duet Development Corp.
  12.  *
  13.  *    Copyright:    (c) 1995 by Apple Computer, Inc., all rights reserved.
  14.  *
  15.  *    Change History (most recent first):
  16.  *        FB8_JRK    Segmentation
  17.  *        Fabio    Changed file name to 8 characters
  18.  *        F3D_RWW    Changed ReadTextString not to call ScanTextBuffer, which
  19.  *                    stripped spaces.
  20.  *        F3A_RWW    TOC stuff works.
  21.  *        F37_RWW    Copy label table so that we can return names with objects.
  22.  *        F2R_RWW    Get rid of dumb curPos field.
  23.  *        F2F_RWW    File created.
  24.  *==============================================================================
  25.  */
  26. #include "MFTEXTRD.H"
  27.  
  28. #include <ctype.h>            /* isspace            */
  29. #include <stddef.h>            /* NULL                */
  30. #include <stdio.h>            /* sscanf            */
  31.  
  32. #include "MF3D.H"
  33. #include "MFERRORS.H"
  34. #include "MFINT64.H"
  35. #include "MFSYSTYP.H"
  36. #include "MFASSERT.H"
  37. #include "MFINTOBJ.H"
  38. #include "MFMEMORY.H"
  39. #include "MFOBJTYP.H"
  40. #include "MFTEXTST.H"
  41. #include "MFTEXTUT.H"
  42.  
  43. #if defined(applec) || defined(__MWERKS__) || defined(THINK_C)
  44. #pragma segment __MF3D__
  45. #endif
  46.  
  47. /*==============================================================================
  48.  *    MF3D_ReadSingleChar
  49.  *
  50.  *    Read a single character from a text metafile.
  51.  *    If we have time, make this a buffered read for better performance.
  52.  *==============================================================================
  53.  */
  54. char
  55. MF3D_ReadSingleChar(
  56.     MF3D_FilePtr    inMetafilePtr)
  57. {
  58.     MF3DErr    error;
  59.     char    c;
  60.  
  61.     error = (*inMetafilePtr->procsRec.readProc)
  62.                     (inMetafilePtr->userFilePtr, sizeof(char), &c);
  63.     if (error != kMF3DNoErr)
  64.         return kMF3DEOFChar;                /* assume EOF on error */
  65.     else
  66.         return c;
  67. }
  68.  
  69. /*==============================================================================
  70.  *    MF3D_ReadUntilCloseParen
  71.  *
  72.  *    Read characters from a file until we get a close parenthesis
  73.  *    that matches the open parenthesis we just read.
  74.  *==============================================================================
  75.  */
  76. MF3DErr
  77. MF3D_ReadUntilCloseParen(
  78.     MF3D_FilePtr    inMetafilePtr)
  79. {
  80.     MF3DUns32    parenCount;
  81.     char        c;
  82.  
  83.     parenCount = 1;
  84.     do
  85.     {    c = MF3D_ReadSingleChar(inMetafilePtr);
  86.         if (c == kMF3D_CommentLineChar)
  87.         {    /* Entering a comment: read to end of line */
  88.             do
  89.             {    c = MF3D_ReadSingleChar(inMetafilePtr);
  90.             } while (strchr(kMF3D_EndOfLineList, c) == NULL && c != kMF3DEOFChar);
  91.         }
  92.         else if (c == kMF3D_StringBeginChar)
  93.         {    /* Entering a string: read to end of string */
  94.             do
  95.             {    c = MF3D_ReadSingleChar(inMetafilePtr);
  96.                 if (c == kMF3D_StringEscapeChar)
  97.                 {    /* If we get the escape character,
  98.                      * then ignore the following character.
  99.                      */
  100.                     MF3D_ReadSingleChar(inMetafilePtr);
  101.                     c = MF3D_ReadSingleChar(inMetafilePtr);
  102.                 }
  103.             } while (c != kMF3D_StringEndChar && c != kMF3DEOFChar);
  104.         }
  105.         else if (c == kMF3D_BeginChar)
  106.         {    ++parenCount;
  107.         }
  108.         else if (c == kMF3D_EndChar)
  109.         {    --parenCount;
  110.         }
  111.     } while (parenCount > 0 && c != kMF3DEOFChar);
  112.  
  113.     return (parenCount == 0 ? kMF3DNoErr : kMF3DErrCantParse);
  114. }
  115.  
  116. /*==============================================================================
  117.  *    MF3D_GetTOCLabels
  118.  *
  119.  *    Broke this out of MF3D_PreprocessTextFile
  120.  *==============================================================================
  121.  */
  122. MF3DErr
  123. MF3D_GetTOCLabels(
  124.     MF3D_FilePtr                    inMetafilePtr,
  125.     MF3DUns32                        inNumTocs,
  126.     MF3DConstBinaryFilePositionPtr    inTocLocations,
  127.     MF3DUns32                        *outNumLabels,
  128.     MF3D_TOCReferencePtr            *outTocLabelNames,
  129.     MF3DUns32                        *outRefSeed,
  130.     MF3DInt32                        *outTypeSeed)
  131. {
  132.     MF3DUns32                        numTocs;
  133.     MF3DConstBinaryFilePositionPtr    tocLocations;
  134.     MF3DUns32                        numLabels;
  135.     MF3D_TOCReferencePtr            tocLabelNames;
  136.     MF3DUns32                        refSeed;
  137.     MF3DInt32                        typeSeed;
  138.     MF3DErr                            result;
  139.  
  140.     tocLocations = inTocLocations;
  141.  
  142.     result = kMF3DNoErr;
  143.     numLabels = 0;
  144.     tocLabelNames = MF3D_Malloc(0);
  145.     refSeed = 0;
  146.     typeSeed = 0;
  147.  
  148.     for (numTocs = inNumTocs; numTocs > 0 && result == kMF3DNoErr; --numTocs)
  149.     {    MF3DTableOfContentsObjPtr    tocPtr;
  150.         MF3D_TOCReferencePtr        tempPtr;
  151.         MF3D_TOCEntryPtr            tocEntryPtr;
  152.         MF3DUns32                    numNewLabels;
  153.  
  154.         tocPtr = NULL;
  155.  
  156.         /* Set the file pointer to the next TOC and get the obj there */
  157.         result = MF3DSeekPosition(inMetafilePtr, *tocLocations);
  158.  
  159.         if (result == kMF3DNoErr)
  160.         {    ++tocLocations;
  161.             result = MF3D_IntReadObject(inMetafilePtr,
  162.                     (MF3DVoidObjPtr *)&tocPtr);
  163.         }
  164.  
  165.         if (result == kMF3DNoErr)
  166.         {    if (tocPtr->objectType != kMF3DObjTableOfContents)
  167.                 result = kMF3DErrCantParse;
  168.         }
  169.  
  170.         if (result == kMF3DNoErr)
  171.         {    if (tocPtr->refSeed > refSeed)
  172.                 refSeed = tocPtr->refSeed;
  173.             if (tocPtr->typeSeed < typeSeed)
  174.                 typeSeed = tocPtr->typeSeed;
  175.             numNewLabels = tocPtr->nEntries;
  176.             MFASSERT(numNewLabels >= 0);
  177.  
  178.             if (numNewLabels > 0)
  179.             {    tempPtr = MF3D_Realloc(tocLabelNames,
  180.                         (numLabels + numNewLabels) * sizeof(*tocLabelNames));
  181.                 if (tempPtr == NULL)
  182.                     result = kMF3DErrOutOfMemory;
  183.                 else
  184.                     tocLabelNames = tempPtr;
  185.             }
  186.         }
  187.  
  188.         if (result == kMF3DNoErr)
  189.         {    /* Make copies of all the labels */
  190.             tocEntryPtr = tocPtr->tocEntries;
  191.  
  192.             for (; numNewLabels > 0; --numNewLabels)
  193.             {    MF3DCStringPtr    ptr;
  194.     
  195.                 MFASSERT(tocEntryPtr != NULL);
  196.                 MFASSERT(tocEntryPtr->objLocation != NULL);
  197.                 MFASSERT(tocEntryPtr->objLocation->format == kMF3DFormatText);
  198.                 ptr = MF3D_DuplicateCString(
  199.                         tocEntryPtr->objLocation->location.text);
  200.                 if (ptr == NULL)
  201.                 {    result = kMF3DErrOutOfMemory;
  202.                     break;
  203.                 }
  204.                 tocLabelNames[numLabels].refID = tocEntryPtr->refID;
  205.                 tocLabelNames[numLabels].ref.name = ptr;
  206.                 ++tocEntryPtr;
  207.                 ++numLabels;
  208.             }
  209.         }
  210.  
  211.         /* Done with this TOC object; so dispose it */
  212.         MF3DDisposeObject((MF3DVoidObjPtr)tocPtr);
  213.     }
  214.  
  215.     *outNumLabels = numLabels;
  216.     *outTocLabelNames = tocLabelNames;
  217.     *outRefSeed = refSeed;
  218.     *outTypeSeed = typeSeed;
  219.  
  220.     return result;
  221. }
  222.  
  223. /*==============================================================================
  224.  *    MF3D_ConvertTableLabels
  225.  *
  226.  *    Convert all the labels in ioObjTable to refIDs.
  227.  *    Also frees any matching label names in ioTocLabelNames.
  228.  *==============================================================================
  229.  */
  230. MF3DErr
  231. MF3D_ConvertTableLabels(
  232.     MF3D_FilePtr                inMetafilePtr,
  233.     MF3DUns32                    inNumLabels,
  234.     MF3D_TOCReferencePtr        ioTocLabelNames,
  235.     MF3DUns32                    inNumObjects,
  236.     MF3D_ObjectTableEntryPtr    ioObjTable)
  237. {
  238.     MF3DUns32                    objCount;
  239.     MF3DUns32                    labelIndex;
  240.     MF3D_ObjectTableEntryPtr    objTablePtr;
  241.     MF3DUns32                    labelLen;
  242.     MF3DCStringPtr                objLabelName, tempPtr;
  243.     MF3DErr                        result;
  244.  
  245.     result = kMF3DNoErr;
  246.  
  247.     objLabelName = MF3D_Malloc(0);
  248.     objTablePtr = ioObjTable;
  249.     for (objCount = inNumObjects; objCount > 0; --objCount)
  250.     {    /* Did we mark this object as having a label? */
  251.         if ((labelLen = objTablePtr->objRefID) > 0)
  252.         {    result = MF3DSeekPosition(inMetafilePtr, objTablePtr->objLocation);
  253.             if (result != kMF3DNoErr)
  254.                 break;
  255.  
  256.             tempPtr = MF3D_Realloc(objLabelName, labelLen);
  257.             if (tempPtr == NULL)
  258.             {    result = kMF3DErrOutOfMemory;
  259.                 break;
  260.             }
  261.             objLabelName = tempPtr;
  262.  
  263.             /* Read the object label name from the metafile */
  264.             --labelLen;            /* get rid of the colon */
  265.             result = (*inMetafilePtr->procsRec.readProc)
  266.                     (inMetafilePtr->userFilePtr, labelLen, objLabelName);
  267.             if (result != kMF3DNoErr)
  268.                 break;
  269.  
  270.             /* Replace the colon with EOS */
  271.             objLabelName[labelLen] = '\0';
  272.  
  273.             /* Compare the label name against all the names in the TOC */
  274.             for (labelIndex = 0; labelIndex < inNumLabels; ++labelIndex)
  275.             {    if (MF3D_CompareLabelNames(objLabelName,
  276.                         ioTocLabelNames[labelIndex].ref.name) == 0)
  277.                 {    objTablePtr->objRefID =
  278.                             ioTocLabelNames[labelIndex].refID;
  279.                     /* We no longer free the name because a copy of the ptr
  280.                      * exists in the metafile (tocStuff.references).
  281.                      */
  282.                     /* MF3D_Free(ioTocLabelNames[labelIndex].name); */
  283.                     ioTocLabelNames[labelIndex].ref.name = NULL;
  284.                     break;
  285.                 }
  286.             }
  287.             if (labelIndex >= inNumLabels)
  288.             {    /* Did not find the label. Just ignore it. */
  289.                 objTablePtr->objRefID = kMF3DUnreferencedLabel;
  290.             }
  291.         }
  292.         ++objTablePtr;
  293.     }
  294.  
  295.     MF3D_Free(objLabelName);
  296.  
  297.     return result;
  298. }
  299.  
  300. /*==============================================================================
  301.  *    MF3D_PreprocessTextFile
  302.  *
  303.  *    We determined that we need to read the whole text file to get the TOC.
  304.  *    As long as we are reading the text file, we might as well store object
  305.  *    locations because they will come in handy when we actually read the objects.
  306.  *
  307.  *    Recipe for spaghetti code:
  308.  *        Write source code on a deadline and then realize halfway through that
  309.  *        some basic assumptions are not true. [In other words, my apologies to
  310.  *        the reader; but nobody is supposed to be reading this code anyway.]
  311.  *
  312.  *    Returns:
  313.  *        kMF3DNoErr                    if preprocess succeeded
  314.  *        kMF3DErrOutOfMemory            if unable to create objTable
  315.  *        kMF3DErrCantParse            if file format is incorrect
  316.  *        kMF3DErrObjHasTooManyLabels    if two or more labels for a single object
  317.  *        kMF3DErrIllegalObjName        if object name was way too long or was not
  318.  *                                        followed by an open parenthesis
  319.  *        any error returned by        MF3DTellPosition()
  320.  *==============================================================================
  321.  */
  322. MF3DErr
  323. MF3D_PreprocessTextFile(
  324.     MF3D_FilePtr    inMetafilePtr)
  325. {
  326.     MF3DUns32                    numObjects;
  327.     MF3D_ObjectTableEntryPtr    objTable;
  328.     MF3DBinaryFilePosition        location;
  329.     MF3DUns32                    numTocs;
  330.     MF3DBinaryFilePositionPtr    tocLocations;
  331.     MF3DUns32                    numLabels, labelIndex;
  332.     MF3D_TOCReferencePtr        tocLabelNames;
  333.     MF3DUns32                    refSeed;
  334.     MF3DInt32                    typeSeed;
  335.     MF3DUns32                    containerDepth;
  336.     MF3DErr                        result;
  337.     char                        c;
  338.  
  339.     MFASSERT(inMetafilePtr != NULL);
  340.  
  341.     /* We have not yet found any objects */
  342.     numObjects = 0;
  343.     objTable = MF3D_Malloc(0);
  344.     containerDepth = 0;    /* Contents objects whose end parens we have to match */
  345.  
  346.     /* We have not yet read any of the Table of Contents */
  347.     numTocs = 0;
  348.     tocLocations = MF3D_Malloc(0);
  349.  
  350.     /* We have no label table yet */
  351.     numLabels = 0;
  352.     tocLabelNames = NULL;
  353.  
  354.     /* We start outside any object (root level) */
  355.  
  356.     /* Somewhat lame, but we have to keep calling tell until we hit
  357.      * something (we want to know where we were when we hit something;
  358.      * not where we are after we hit it).
  359.      */
  360.     while ((result = MF3DTellPosition(inMetafilePtr, &location)) == kMF3DNoErr)
  361.     {    /* Read until there is nothing more to read */
  362.         if ((c = MF3D_ReadSingleChar(inMetafilePtr)) == kMF3DEOFChar)
  363.             break;                    /* ### REAL LOOP EXIT ### */
  364.  
  365.         /* Check for end of contents object */
  366.         if (c == kMF3D_EndChar)
  367.         {    if (containerDepth == 0)
  368.             {    result = kMF3DErrCantParse;
  369.                 goto PreprocessTextFileAbort;
  370.             }
  371.             --containerDepth;
  372.         }
  373.         /* F7K_PAM added this 'else' to handle reading of comments */
  374.         else if (c == kMF3D_CommentLineChar)
  375.         {       /* Entering a comment: read to end of line */
  376.             do
  377.             {    c = MF3D_ReadSingleChar(inMetafilePtr);
  378.             } while (strchr(kMF3D_EndOfLineList, c) == NULL && c != kMF3DEOFChar);
  379.         }
  380.         /* Look for a text label or object name */
  381.         else if (!isspace(c))
  382.         {    unsigned int    objNameCharPos;
  383.             char            objName[kMF3D_MaxObjNameLength + 1];
  384.  
  385.             if (numObjects % kMF3D_ObjTableChunk == 0)
  386.             {    MF3D_ObjectTableEntryPtr    tempPtr;
  387.                 tempPtr = MF3D_Realloc(objTable,
  388.                         (numObjects + kMF3D_ObjTableChunk) * sizeof(*objTable));
  389.                 if (tempPtr == NULL)
  390.                 {    result = kMF3DErrOutOfMemory;
  391.                     goto PreprocessTextFileAbort;
  392.                 }
  393.                 objTable = tempPtr;
  394.             }
  395.  
  396.             /* Store location of beginning of object */
  397.             AssignInt64(objTable[numObjects].objLocation, location);
  398.             objTable[numObjects].objRefID = 0;
  399.  
  400.             objNameCharPos = 0;
  401.  
  402.             do
  403.             {    if (objNameCharPos < kMF3D_MaxObjNameLength)
  404.                     objName[objNameCharPos++] = c;
  405.  
  406.                 c = MF3D_ReadSingleChar(inMetafilePtr);
  407.  
  408.                 if (isspace(c) || c == kMF3D_BeginChar)
  409.                 {    /* Object header name has ended */
  410.                     if (objNameCharPos >= kMF3D_MaxObjNameLength)
  411.                     {    result = kMF3DErrIllegalObjName;
  412.                         goto PreprocessTextFileAbort;
  413.                     }
  414.                     objName[objNameCharPos] = '\0';
  415.                     /* Make sure we actually get the open paren */
  416.                     while (c != kMF3D_BeginChar)
  417.                     {    if (!isspace(c) || c == kMF3DEOFChar)
  418.                         {    result = kMF3DErrIllegalObjName;
  419.                             goto PreprocessTextFileAbort;
  420.                         }
  421.                         c = MF3D_ReadSingleChar(inMetafilePtr);
  422.                     }
  423.                     /* Is this a table of contents object? */
  424.                     if (MF3D_CompareObjNames(objName, kMF3DObjTableOfContentsText) == 0)
  425.                     {    /* We found a TOC object. We will want to find
  426.                          * this later; so save the index.
  427.                          */
  428.                         MF3DBinaryFilePositionPtr    tempPtr;
  429.                         tempPtr = MF3D_Realloc(tocLocations,
  430.                                 (numTocs + 1) * sizeof(*tocLocations));
  431.                         if (tempPtr == NULL)
  432.                         {    result = kMF3DErrOutOfMemory;
  433.                             goto PreprocessTextFileAbort;
  434.                         }
  435.                         tocLocations = tempPtr;
  436.                         AssignInt64(tocLocations[numTocs], location);
  437.                         ++numTocs;
  438.  
  439.                         /* Skip to the matching close paren */
  440.                         result = MF3D_ReadUntilCloseParen(inMetafilePtr);
  441.                         break;                /* ### LOOP EXIT ### */
  442.                     }
  443.                     else if (MF3D_CompareObjNames(objName,
  444.                             kMF3DObjContainerText) == 0)
  445.                     {    /* We found a Container object.
  446.                          * Ignore it. AND read no further.
  447.                          */
  448.                         ++containerDepth;
  449.                         break;                /* ### LOOP EXIT ### */
  450.                     }
  451.                     else
  452.                     {    /* We have a non-table of contents object.
  453.                          * Just read until we get the matching end paren.
  454.                          */
  455.                         result = MF3D_ReadUntilCloseParen(inMetafilePtr);
  456.                         break;                /* ### LOOP EXIT ### */
  457.                     }
  458.                     if (result != kMF3DNoErr)
  459.                         goto PreprocessTextFileAbort;
  460.                 }
  461.                 else if (c == kMF3D_LabelChar)
  462.                 {    /* First time through, we store labels as lengths */
  463.                     MF3DBinaryFilePosition    endLabelLoc;
  464.  
  465.                     result = MF3DTellPosition(inMetafilePtr, &endLabelLoc);
  466.  
  467.                     if (objTable[numObjects].objRefID != 0)
  468.                         result = kMF3DErrObjHasTooManyLabels;
  469.  
  470.                     if (result != kMF3DNoErr)
  471.                         goto PreprocessTextFileAbort;
  472.  
  473.                     /* length of label, including colon */
  474.                     objTable[numObjects].objRefID = SubtractUns64(endLabelLoc,
  475.                             location);
  476.  
  477.                     /* reset name pointer and continue looking */
  478.                     objNameCharPos = 0;
  479.                     do
  480.                     {    c = MF3D_ReadSingleChar(inMetafilePtr);
  481.  
  482.                         /* FB4_JRK */
  483.                         if (c == kMF3D_CommentLineChar)
  484.                         {       /* Entering a comment: read to end of line */
  485.                             do
  486.                             {    c = MF3D_ReadSingleChar(inMetafilePtr);
  487.                             } while (strchr(kMF3D_EndOfLineList, c) == NULL && c != kMF3DEOFChar);
  488.                         }
  489.                     } while (isspace(c));
  490.                 }
  491.                 else if (c == kMF3DEOFChar)
  492.                 {    result = kMF3DErrCantParse;
  493.                     goto PreprocessTextFileAbort;
  494.                 }
  495.             } while (1);
  496.  
  497.             ++numObjects;
  498.         }
  499.     }
  500.  
  501.     if (numObjects == 0)
  502.         result = kMF3DErrNoObjectsFound;
  503.  
  504.     if (result == kMF3DNoErr && containerDepth > 0)
  505.         result = kMF3DErrCantParse;
  506.  
  507.     /* Readjust the object table from its chunky size */
  508.     if (result == kMF3DNoErr)
  509.     {    MF3D_ObjectTableEntryPtr    tempPtr;
  510.  
  511.         tempPtr = MF3D_Realloc(objTable, (numObjects + 1) * sizeof(*objTable));
  512.         if (tempPtr == NULL)
  513.         {    result = kMF3DErrOutOfMemory;
  514.         }
  515.         else
  516.         {    objTable = tempPtr;
  517.             /* Store the file length here */
  518.             AssignInt64(objTable[numObjects].objLocation, location);
  519.             objTable[numObjects].objRefID = 0;
  520.  
  521.             inMetafilePtr->objTable.numObjects = numObjects;
  522.             inMetafilePtr->objTable.objects = objTable;
  523.         }
  524.     }
  525.  
  526.     /* Okay, if we get this far, we have read through the entire file
  527.      * successfully!
  528.      *
  529.      * Now, we can use all our fancy read routines because we have
  530.      * all the object sizes.
  531.      *
  532.      * So, read in all the TableOfContents objects and convert all
  533.      * the object labels to refIDs.
  534.      */
  535.     if (result == kMF3DNoErr)
  536.     {    result = MF3D_GetTOCLabels(inMetafilePtr, numTocs, tocLocations,
  537.                 &numLabels, &tocLabelNames, &refSeed, &typeSeed);
  538.     }
  539.  
  540.     /* Save the label table info because we will need it for the
  541.      * names later.
  542.      * NOTE: We can probably rewrite to eliminate MF3D_ConvertTableLabels now,
  543.      * if we want to.
  544.      */
  545.     if (result == kMF3DNoErr)
  546.     {    MF3DSize                tocLabelTableSize;
  547.         MF3D_TOCReferencePtr    tempPtr;
  548.  
  549.         inMetafilePtr->tocStuff.refSeed = refSeed;
  550.         inMetafilePtr->tocStuff.typeSeed = typeSeed;
  551.         inMetafilePtr->tocStuff.numReferences = numLabels;
  552.         tocLabelTableSize = numLabels *
  553.                 sizeof(*inMetafilePtr->tocStuff.references);    
  554.         tempPtr = MF3D_Malloc(tocLabelTableSize);
  555.         if (tempPtr == NULL)
  556.         {    result = kMF3DErrOutOfMemory;
  557.         }
  558.         else
  559.         {    inMetafilePtr->tocStuff.references = tempPtr;
  560.             memcpy(inMetafilePtr->tocStuff.references, tocLabelNames,
  561.                     tocLabelTableSize);
  562.         }
  563.     }
  564.  
  565.     /* Now, go through objTable and change the label lengths to actual
  566.      * ref IDs!
  567.      */
  568.     if (result == kMF3DNoErr)
  569.     {    result = MF3D_ConvertTableLabels(inMetafilePtr, numLabels,
  570.                 tocLabelNames, numObjects, objTable);
  571.     }
  572.  
  573. PreprocessTextFileAbort:
  574.     /* Free any TOC labels that did not find matches */
  575.     for (labelIndex = 0; labelIndex < numLabels; ++labelIndex)
  576.     {    MF3D_Free(tocLabelNames[labelIndex].ref.name);
  577.     }
  578.  
  579.     MF3D_Free(tocLabelNames);
  580.     MF3D_Free(tocLocations);
  581.  
  582.     if (result != kMF3DNoErr)
  583.     {    /* Free the objTable only if we are quitting */
  584.         MF3D_Free(objTable);
  585.     }
  586.     else
  587.     {    MF3DBinaryFilePosition    firstObj;
  588.  
  589.         MF3D_Free(inMetafilePtr->readBuffer.buf);
  590.         inMetafilePtr->readBuffer.buf = NULL;
  591.  
  592.         /* Reset the file pointer to the beginning */
  593.         AssignInt64(firstObj, objTable[0].objLocation);
  594.         result = MF3DSeekPosition(inMetafilePtr, firstObj);
  595.     }
  596.  
  597.     return result;
  598. }
  599.  
  600. /*==============================================================================
  601.  *    MF3D_GetRefNameT
  602.  *
  603.  *    Get reference name
  604.  *
  605.  *    Allocates and returns CStringPtr or NULL if no match found.
  606.  *==============================================================================
  607.  */
  608. MF3DCStringPtr
  609. MF3D_GetRefNameT(
  610.     MF3D_FilePtr        inMetafilePtr,
  611.     MF3DReferenceID        inRefID)
  612. {
  613.     MF3DUns32                refIndex;
  614.     MF3D_TOCReferencePtr    labelTablePtr;
  615.     MF3DCStringPtr            result;
  616.  
  617.     result = NULL;
  618.  
  619.     labelTablePtr = inMetafilePtr->tocStuff.references;
  620.     MFASSERT(inMetafilePtr->tocStuff.numReferences == 0 ||
  621.             labelTablePtr != NULL);
  622.  
  623.     for (refIndex = inMetafilePtr->tocStuff.numReferences;
  624.             refIndex > 0; --refIndex)
  625.     {    if (labelTablePtr->refID == inRefID)
  626.         {    result = MF3D_DuplicateCString(labelTablePtr->ref.name);
  627.             break;
  628.         }
  629.         ++labelTablePtr;
  630.     }
  631.  
  632.     return result;
  633. }
  634.  
  635. /*==============================================================================
  636.  *    MF3D_PostprocessTextFile
  637.  *
  638.  *    Dispose of TOC structures
  639.  *==============================================================================
  640.  */
  641. MF3DErr
  642. MF3D_PostprocessTextFile(
  643.     MF3D_FilePtr        inMetafilePtr)
  644. {
  645.     MF3DUns32                refIndex;
  646.     MF3D_TOCReferencePtr    labelTablePtr;
  647.     MF3DBinaryFilePosition    zero;
  648.  
  649.     /* Do not close things if we were just resolving a reference in this file */
  650.     SetInt64ToZero(zero);
  651.     if (CompareInt64(inMetafilePtr->resStuff.returnLoc, zero) == 0)
  652.     {    labelTablePtr = inMetafilePtr->tocStuff.references;
  653.         MFASSERT(inMetafilePtr->tocStuff.numReferences == 0 ||
  654.                 labelTablePtr != NULL);
  655.     
  656.         for (refIndex = inMetafilePtr->tocStuff.numReferences;
  657.                 refIndex > 0; --refIndex)
  658.         {    MF3D_Free(labelTablePtr->ref.name);
  659.             ++labelTablePtr;
  660.         }
  661.  
  662.         MF3D_Free(inMetafilePtr->tocStuff.references);
  663.         MF3D_Free(inMetafilePtr->objTable.objects);
  664.     }
  665.  
  666.     return kMF3DNoErr;
  667. }
  668.  
  669. /*==============================================================================
  670.  *    MF3D_CompareObjNames
  671.  *
  672.  *    Match the name of an object. Return 0 if it matches; nonzero otherwise.
  673.  *==============================================================================
  674.  */
  675. MF3DInt32
  676. MF3D_CompareObjNames(
  677.     const char        *obj1,
  678.     const char        *obj2)
  679. {
  680.     return MF3D_CompareLabelNames(obj1, obj2);
  681. }
  682.  
  683. /*==============================================================================
  684.  *    MF3D_CompareLabelNames
  685.  *
  686.  *    Match the name of a label. Return 0 if it matches; nonzero otherwise.
  687.  *==============================================================================
  688.  */
  689. MF3DInt32
  690. MF3D_CompareLabelNames(
  691.     const char        *label1,
  692.     const char        *label2)
  693. {
  694.     MFASSERT(label1 != NULL || label2 != NULL);
  695.  
  696.     if (label1 == NULL || label2 == NULL)
  697.         return 1;
  698.     return MF3D_CmpStrInsensitive(label1, label2);
  699. }
  700.  
  701. /*==============================================================================
  702.  *    MF3D_ScanTextBuffer
  703.  *
  704.  *    Basically we just need something that does fscanf for one argument.
  705.  *    After reading the argument, skip spaces and comments that follow.
  706.  *==============================================================================
  707.  */
  708. MF3DErr
  709. MF3D_ScanTextBuffer(
  710.     MF3D_FilePtr    inMetafilePtr,
  711.     const char        *inFormatStr,
  712.     void            *outBuffer)
  713. {
  714.     char        *bufPtr;
  715.     MF3DUns32    bufPos;
  716.     int            numCharsRead;
  717.     char        formatStr[kMF3D_MaxFormatLength + 2];
  718.     MF3DErr        result;
  719.  
  720.     MFASSERT(inMetafilePtr->readBuffer.buf != NULL);
  721.     MFASSERT(strlen(inFormatStr) <= kMF3D_MaxFormatLength);
  722.  
  723.     result = kMF3DNoErr;
  724.  
  725.     bufPos = inMetafilePtr->readBuffer.bufPos;
  726.     bufPtr = inMetafilePtr->readBuffer.buf;
  727.  
  728.     /* Add %n to the format string, so that we can tell how many characters
  729.      * get read.
  730.      */
  731.     strcpy(formatStr, inFormatStr);
  732.     strcat(formatStr, "%n");
  733.     numCharsRead = 0;
  734.     sscanf(&bufPtr[bufPos], formatStr, outBuffer, &numCharsRead);
  735.  
  736.     bufPos += numCharsRead;
  737.     MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  738.  
  739.     if (numCharsRead <= 0)
  740.         result = kMF3DErrCantParse;
  741.  
  742.     MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  743.     inMetafilePtr->readBuffer.bufPos = bufPos;
  744.  
  745.     if (result == kMF3DNoErr)
  746.         result = MF3D_SkipWhitespace(inMetafilePtr);
  747.  
  748.     return result;
  749. }
  750.  
  751. /*==============================================================================
  752.  *    MF3D_SkipWhitespace
  753.  *
  754.  *    Read and ignore whitespace from text buffer
  755.  *==============================================================================
  756.  */
  757. MF3DErr
  758. MF3D_SkipWhitespace(
  759.     MF3D_FilePtr    inMetafilePtr)
  760. {
  761.     char        *bufPtr;
  762.     MF3DUns32    bufPos;
  763.     int            numCharsRead;
  764.     char        commentChar[2];
  765.  
  766.     MFASSERT(inMetafilePtr->readBuffer.buf != NULL);
  767.  
  768.     bufPos = inMetafilePtr->readBuffer.bufPos;
  769.     bufPtr = inMetafilePtr->readBuffer.buf;
  770.  
  771.     /* Skip over any whitespace */
  772.     numCharsRead = 0;    /* init to 0 in case there is no whitespace */
  773.     sscanf(&bufPtr[bufPos], "%*[" kMF3D_WhitespaceList "]%n", &numCharsRead);
  774.     bufPos += numCharsRead;
  775.     MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  776.  
  777.     /* If the next character is the comment character, skip the rest
  778.      * of the line.
  779.      */
  780.     while (sscanf(&bufPtr[bufPos],
  781.                 "%1[" kMF3D_CommentLineStr "]"        /* grab one # char        */
  782.                 "%n",                                /* numChars read        */
  783.                 &commentChar, &numCharsRead) > 0)
  784.     {    bufPos += numCharsRead;
  785.         numCharsRead = 0;
  786.         sscanf(&bufPtr[bufPos],
  787.                 "%*[^" kMF3D_EndOfLineList "]%n",    /* ignore rest to EOL    */
  788.                 &numCharsRead);
  789.         bufPos += numCharsRead;
  790.         MFASSERT(numCharsRead > 0);            /* should have been a newline */
  791.         numCharsRead = 0;
  792.         sscanf(&bufPtr[bufPos],
  793.                 "%*[" kMF3D_WhitespaceList "]%n",    /* skip whitespace        */
  794.                 &numCharsRead);
  795.         bufPos += numCharsRead;
  796.     }
  797.  
  798.     MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  799.     inMetafilePtr->readBuffer.bufPos = bufPos;
  800.  
  801.     return kMF3DNoErr;
  802. }
  803.  
  804. /*==============================================================================
  805.  *    MF3D_ReadOpenParen
  806.  *
  807.  *    Read an open paren character and return
  808.  *==============================================================================
  809.  */
  810. MF3DErr
  811. MF3D_ReadOpenParen(
  812.     MF3D_FilePtr    inMetafilePtr)
  813. {
  814.     char    openParen[2];
  815.  
  816.     return MF3D_ScanTextBuffer(inMetafilePtr, "%1[" kMF3D_BeginCharStr "]",
  817.             openParen);
  818. }
  819.  
  820. /*==============================================================================
  821.  *    MF3D_SkipText
  822.  *
  823.  *    Skip over text (used for skipping over resolution labels).
  824.  *    ###NOTE### will return an error if not least two characters of text
  825.  *==============================================================================
  826.  */
  827. MF3DErr
  828. MF3D_SkipText(
  829.     MF3D_FilePtr    inMetafilePtr)
  830. {
  831.     /* ScanTextBuffer expects at least one void * parameter */
  832.     char    junkChar[2];
  833.  
  834.     return MF3D_ScanTextBuffer(inMetafilePtr,
  835.             "%1c"    /* for junkChar */
  836.             "%*[^" kMF3D_BeginCharStr kMF3D_WhitespaceList "]",
  837.             junkChar);
  838. }
  839.  
  840. /*==============================================================================
  841.  *    MF3D_ReadObjectStuff
  842.  *
  843.  *    Read the object name and get the objStuff.
  844.  *==============================================================================
  845.  */
  846. MF3DErr
  847. MF3D_ReadObjectStuff(
  848.     MF3D_FilePtr        inMetafilePtr,
  849.     MF3D_ObjStuffPtr    *outObjectStuffPtr,
  850.     MF3DObjType            *outObjectType)
  851. {
  852.     char        objName[kMF3D_MaxObjNameLength];
  853.     MF3DErr        result;
  854.  
  855.     result = MF3D_ScanTextBuffer(inMetafilePtr,
  856.             "%[^" kMF3D_BeginCharStr kMF3D_EndCharStr kMF3D_WhitespaceList "]",
  857.             objName);
  858.  
  859.     if (result == kMF3DNoErr)
  860.     {    result = MF3D_FindObjectFromName(objName, outObjectStuffPtr,
  861.                 outObjectType);
  862.     }
  863.  
  864.     return result;
  865. }
  866.  
  867. /*==============================================================================
  868.  *    MF3D_ReadTextString
  869.  *
  870.  *    Read a text string
  871.  *    *outStringPtr only valid if kMF3DNoErr returned.
  872.  *==============================================================================
  873.  */
  874. MF3DErr
  875. MF3D_ReadTextString(
  876.     MF3D_FilePtr        inMetafilePtr,
  877.     MF3DCStringPtr        *outStringPtr)
  878. {
  879.     MF3DErr                result;
  880.     MF3D_BuildString    tempStr;
  881.     char                *bufPtr;
  882.     char                c;
  883.     MF3DUns32            bufPos;
  884.     int                    numCharsRead;
  885.     
  886.  
  887.     result = kMF3DNoErr;
  888.  
  889.     bufPos = inMetafilePtr->readBuffer.bufPos;
  890.     bufPtr = inMetafilePtr->readBuffer.buf;
  891.  
  892.     numCharsRead = 0;
  893.     sscanf(&bufPtr[bufPos], "%1[" kMF3D_StringBeginStr "]%n", &c,
  894.             &numCharsRead);
  895.  
  896.     if (numCharsRead <= 0)
  897.         result = kMF3DErrUnquotedString;
  898.  
  899.     if (result == kMF3DNoErr)
  900.     {    bufPos += numCharsRead;
  901.         MFASSERT(c == kMF3D_StringBeginChar);
  902.         MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  903.  
  904.         result = MF3D_BuildString_New(&tempStr);
  905.     }
  906.  
  907.     /* Scan the text buffer, copying characters until we hit the end quote */
  908.     while (result == kMF3DNoErr)
  909.     {    numCharsRead = 0;
  910.         sscanf(&bufPtr[bufPos], "%c%n", &c, &numCharsRead);
  911.         if (numCharsRead <= 0)
  912.             result = kMF3DErrCantParse;
  913.  
  914.         if (result == kMF3DNoErr)
  915.         {    bufPos += numCharsRead;
  916.             MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  917.  
  918.             if (c == kMF3D_StringEndChar)
  919.             {    MF3D_BuildString_EndString(&tempStr);
  920.                 /* Copy the string pointer. Do NOT delete. */
  921.                 *outStringPtr = tempStr.str;
  922.                 break;        /* ### NORMAL EXIT IS HERE ### */
  923.             }
  924.             else if (c == kMF3D_StringEscapeChar)
  925.             {    sscanf(&bufPtr[bufPos], "%c%n", &c, &numCharsRead);
  926.                 if (numCharsRead <= 0)
  927.                     result = kMF3DErrCantParse;
  928.                 else
  929.                     bufPos += numCharsRead;
  930.  
  931.                 if (result == kMF3DNoErr)
  932.                 {    switch (c)
  933.                     {    case 'a':    c = '\a'; break;
  934.                         case 'b':    c = '\b'; break;
  935.                         case 'f':    c = '\f'; break;
  936.                         case 'n':    c = '\n'; break;
  937.                         case 'r':    c = '\r'; break;
  938.                         case 't':    c = '\t'; break;
  939.                         case 'v':    c = '\v'; break;
  940.                         case '0':    /* NOTE: ### \123 NOT SUPPORTED ### */
  941.                         case '1':
  942.                         case '2':
  943.                         case '3':
  944.                         case '4':
  945.                         case '5':
  946.                         case '6':
  947.                         case '7':
  948.                         case '8':
  949.                         case '9':
  950.                         case 'x':    /* NOTE: ### \x0F NOT SUPPORTED ### */
  951.                         default:    break;
  952.                     }
  953.                     MF3D_BuildString_AddChar(&tempStr, c);
  954.                 }
  955.             }
  956.             else
  957.             {    MF3D_BuildString_AddChar(&tempStr, c);
  958.             }
  959.         }
  960.  
  961.         if (result != kMF3DNoErr)
  962.         {    /* Should already be free */
  963.             MFASSERT(tempStr.str == NULL);
  964.         }
  965.     }
  966.  
  967.     MFASSERT(bufPos <= inMetafilePtr->readBuffer.bufSize);
  968.     inMetafilePtr->readBuffer.bufPos = bufPos;
  969.  
  970.     if (result == kMF3DNoErr)
  971.         result = MF3D_SkipWhitespace(inMetafilePtr);
  972.  
  973.     return result;
  974. }
  975.  
  976. /*==============================================================================
  977.  *    MF3D_ReadTextLabel
  978.  *
  979.  *    Read an unquoted text string
  980.  *    *outStringPtr only valid if kMF3DNoErr returned.
  981.  *==============================================================================
  982.  */
  983. MF3DErr
  984. MF3D_ReadTextLabel(
  985.     MF3D_FilePtr        inMetafilePtr,
  986.     MF3DCStringPtr        *outStringPtr)
  987. {
  988.     MF3DErr                result;
  989.     MF3D_BuildString    tempStr;
  990.  
  991.     result = MF3D_BuildString_New(&tempStr);
  992.  
  993.     /* Scan the text buffer, copying characters until we hit a right arrow */
  994.     while (result == kMF3DNoErr)
  995.     {    char        c;
  996.  
  997.         result = MF3D_ScanTextBuffer(inMetafilePtr,
  998.             "%c", &c);
  999.         if (result == kMF3DNoErr)
  1000.         {    if (c == kMF3D_FilePtrChar)
  1001.             {    MF3D_BuildString_EndString(&tempStr);
  1002.                 /* Copy the string pointer. Do NOT delete. */
  1003.                 *outStringPtr = tempStr.str;
  1004.                 break;        /* ### NORMAL EXIT IS HERE ### */
  1005.             }
  1006.             else
  1007.             {    MF3D_BuildString_AddChar(&tempStr, c);
  1008.             }
  1009.         }
  1010.  
  1011.         if (result != kMF3DNoErr)
  1012.         {    /* Should already be free */
  1013.             MFASSERT(tempStr.str == NULL);
  1014.         }
  1015.     }
  1016.  
  1017.     return result;
  1018. }
  1019.  
  1020. /*==============================================================================
  1021.  *    MF3D_BuildString_New
  1022.  *    MF3D_BuildString_AddChar
  1023.  *    MF3D_BuildString_EndString
  1024.  *    MF3D_BuildString_Delete
  1025.  *
  1026.  *    Temporary routines to dynamically build a string of unknown length.
  1027.  *==============================================================================
  1028.  */
  1029. MF3DErr
  1030. MF3D_BuildString_New(
  1031.     MF3D_BuildString    *outStringPtr)
  1032. {
  1033.     outStringPtr->str = MF3D_Malloc(0);
  1034.     outStringPtr->pos = 0;
  1035.     return kMF3DNoErr;
  1036. }
  1037.  
  1038. MF3DErr
  1039. MF3D_BuildString_AddChar(
  1040.     MF3D_BuildString    *ioStringPtr,
  1041.     char                inAddChar)
  1042. {
  1043.     MF3DErr    result;
  1044.  
  1045.     result = kMF3DNoErr;
  1046.     if ((ioStringPtr->pos % kMF3D_StringBufferChunk) == 0)
  1047.     {    MF3DCStringPtr    tempPtr;
  1048.  
  1049.         tempPtr = MF3D_Realloc(ioStringPtr->str,
  1050.                 ioStringPtr->pos + kMF3D_StringBufferChunk);
  1051.         if (tempPtr == NULL)
  1052.         {    MF3D_BuildString_Delete(ioStringPtr);
  1053.             result = kMF3DErrOutOfMemory;
  1054.         }
  1055.         else
  1056.             ioStringPtr->str = tempPtr;
  1057.     }
  1058.  
  1059.     if (result == kMF3DNoErr)
  1060.         ioStringPtr->str[ioStringPtr->pos++] = inAddChar;
  1061.  
  1062.     return result;
  1063. }
  1064.  
  1065. MF3DErr
  1066. MF3D_BuildString_EndString(
  1067.     MF3D_BuildString    *ioStringPtr)
  1068. {
  1069.     MF3DErr    result;
  1070.  
  1071.     result = MF3D_BuildString_AddChar(ioStringPtr, '\0');
  1072.  
  1073.     if (result == kMF3DNoErr)
  1074.     {    ioStringPtr->str = MF3D_Realloc(ioStringPtr->str, ioStringPtr->pos);
  1075.  
  1076.         /* pointer should still be valid because we never realloc more */
  1077.         MFASSERT(ioStringPtr->str != NULL);
  1078.     }
  1079.  
  1080.     return result;
  1081. }
  1082.  
  1083. MF3DErr
  1084. MF3D_BuildString_Delete(
  1085.     MF3D_BuildString    *ioStringPtr)
  1086. {
  1087.     MF3D_Free(ioStringPtr->str);
  1088.     ioStringPtr->str = NULL;
  1089.     return kMF3DNoErr;
  1090. }
  1091.  
  1092. /*==============================================================================
  1093.  *    MF3D_NumToString
  1094.  *
  1095.  *    Convert an unsigned number to its decimal string equivalent
  1096.  *==============================================================================
  1097.  */
  1098. void
  1099. MF3D_NumToString(
  1100.     MF3DUns32        inNumber,
  1101.     MF3DCStringPtr    outString)
  1102. {
  1103.     MF3DUns32    n, mod;
  1104.     char        revString[kMF3D_MaxDigitsInUns32 + 1];
  1105.     int            i;
  1106.  
  1107.     n = inNumber;
  1108.     revString[i = kMF3D_MaxDigitsInUns32] = '\0';
  1109.  
  1110.     while (n > 0)
  1111.     {    MFASSERT(i > 0);
  1112.  
  1113.         mod = n - ((n/10) * 10);
  1114.  
  1115.         /* Make no assumptions about character ordering */
  1116.         switch (mod)
  1117.         {    case 0:    revString[--i] = '0'; break;
  1118.             case 1:    revString[--i] = '1'; break;
  1119.             case 2:    revString[--i] = '2'; break;
  1120.             case 3:    revString[--i] = '3'; break;
  1121.             case 4:    revString[--i] = '4'; break;
  1122.             case 5:    revString[--i] = '5'; break;
  1123.             case 6:    revString[--i] = '6'; break;
  1124.             case 7:    revString[--i] = '7'; break;
  1125.             case 8:    revString[--i] = '8'; break;
  1126.             case 9:    revString[--i] = '9'; break;
  1127.             default: MFASSERT(0); break;
  1128.         }
  1129.         n /= 10;
  1130.     }
  1131.  
  1132.     strcpy(outString, &revString[i]);
  1133. }
  1134.  
  1135. /*==============================================================================
  1136.  *    MF3D_TextToHex
  1137.  *
  1138.  *    Convert a text character to its hexadecimal equivalent
  1139.  *==============================================================================
  1140.  */
  1141. MF3DUns8
  1142. MF3D_TextToHex(
  1143.     char inChar)
  1144. {
  1145.     /* Make no assumptions about character ordering */
  1146.     switch(inChar)
  1147.     {    case '0':    return(0);
  1148.         case '1':    return(1);
  1149.         case '2':    return(2);
  1150.         case '3':    return(3);
  1151.         case '4':    return(4);
  1152.         case '5':    return(5);
  1153.         case '6':    return(6);
  1154.         case '7':    return(7);
  1155.         case '8':    return(8);
  1156.         case '9':    return(9);
  1157.         case 'A':
  1158.         case 'a':    return(10);
  1159.         case 'B':
  1160.         case 'b':    return(11);
  1161.         case 'C':
  1162.         case 'c':    return(12);
  1163.         case 'D':
  1164.         case 'd':    return(13);
  1165.         case 'E':
  1166.         case 'e':    return(14);
  1167.         case 'F':
  1168.         case 'f':    return(15);
  1169.         default:    MFASSERT(0); return(0);
  1170.     }
  1171. }
  1172.